package com.xjrsoft.module.iot.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.TypeReference;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.xjrsoft.common.constant.GlobalConstant;
import com.xjrsoft.common.enums.IotProtocolEnum;
import com.xjrsoft.common.mqtt.OpcUaClientService;
import com.xjrsoft.common.utils.IotUtil;
import com.xjrsoft.common.utils.RedisUtil;
import com.xjrsoft.module.iot.entity.IotDic;
import com.xjrsoft.module.iot.entity.IotLink;
import com.xjrsoft.module.iot.mapper.IotDicMapper;
import com.xjrsoft.module.iot.service.IIotDicService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xjrsoft.module.iot.service.IIotLinkService;
import lombok.AllArgsConstructor;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author tzx
 * @since 2024-04-10
 */
@Service
@AllArgsConstructor
public class IotDicServiceImpl extends MPJBaseServiceImpl<IotDicMapper, IotDic> implements IIotDicService {

    private final IIotLinkService iotLinkService;

    private final RedisUtil redisUtil;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addIotDic(IotDic iotDic) {

        save(iotDic);

        List<IotDic> dicList = redisUtil.get(GlobalConstant.IOT_DIC_CACHE_KEY, new TypeReference<List<IotDic>>() {
        });

        dicList.add(iotDic);

        redisUtil.set(GlobalConstant.IOT_DIC_CACHE_KEY,dicList);


        IotLink link = iotLinkService.getById(iotDic.getLinkId());
        if(link.getProtocolType() == IotProtocolEnum.MQTT.getCode()){
            IotUtil.setUpdate(Boolean.TRUE);
        }
        else{
            OpcUaClient opcUaClient = IotUtil.cacheOpcUaClientMap.get(link.getId());


            List<IotDic> linkDicList =  dicList.stream().filter(dic -> dic.getLinkId().equals(link.getId())).collect(Collectors.toList());

            OpcUaClientService opcUaClientService = new OpcUaClientService();
            //在回调方法中重新订阅
            opcUaClient.getSubscriptionManager().clearSubscriptions();

            for (IotDic dic : linkDicList) {
                // 订阅指定节点
                try {
                    opcUaClientService.subscribe(opcUaClient, 2, dic.getName(), linkDicList,false);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }

        }

        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateIotDic(IotDic iotDic) {

        updateById(iotDic);

        List<IotDic> dicList = redisUtil.get(GlobalConstant.IOT_DIC_CACHE_KEY, new TypeReference<List<IotDic>>() {
        });

        dicList.removeIf(dic -> dic.getId().equals(iotDic.getId()));

        dicList.add(iotDic);

        redisUtil.set(GlobalConstant.IOT_DIC_CACHE_KEY,dicList);

        IotLink link = iotLinkService.getById(iotDic.getLinkId());
        if(link.getProtocolType() == IotProtocolEnum.MQTT.getCode()){
            IotUtil.setUpdate(Boolean.TRUE);
        }
        else{
            OpcUaClient opcUaClient = IotUtil.cacheOpcUaClientMap.get(link.getId());


            List<IotDic> linkDicList =  dicList.stream().filter(dic -> dic.getLinkId().equals(link.getId())).collect(Collectors.toList());

            OpcUaClientService opcUaClientService = new OpcUaClientService();
            //在回调方法中重新订阅
            opcUaClient.getSubscriptionManager().clearSubscriptions();

            for (IotDic dic : linkDicList) {
                // 订阅指定节点
                try {
                    opcUaClientService.subscribe(opcUaClient, 2, dic.getName(), linkDicList,false);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }

        }

        return Boolean.TRUE;
    }
}
